package interpreter;

import interpreter.impl.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

/**
 * 环境类
 */
public class Context {
    protected static final Map<String, Integer> level = new HashMap<>();

    static {
        level.put("+", 1);
        level.put("-", 2);
        level.put("*", 3);
        level.put("/", 4);
    }

    private final String context;
    //操作桟
    Stack<Node> stack = new Stack<>();
    //操作符桟
    Stack<String> operation = new Stack<>();
    //表达式
    private Node expression;

    public Context(String context) {
        this.context = context;
    }


    /**
     * 分别取出操作符栈中操作符，和数值栈中的两个操作数进行组合计算，最终得到唯一的结果
     */
    public Node getExpression() {
        while (!operation.empty()) {
            switch (operation.pop()) {
                case "/":
                    Node right = stack.pop();
                    Node left = stack.pop();
                    expression = new DivNode(left, right);
                    stack.push(expression);
                    break;
                case "*":
                    expression = new MulNode(stack.pop(), stack.pop());
                    stack.push(expression);
                    break;
                case "-":
                    Node rightNode = stack.pop();
                    Node leftNode = stack.pop();
                    expression = new SubNode(leftNode, rightNode);
                    stack.push(expression);
                    break;
                default:
                    expression = new AddNode(stack.pop(), stack.pop());
                    stack.push(expression);
                    break;
            }
        }
        return stack.peek();

    }
    /**
     * 通过解析原始算法字符串，决定操作符栈中运算符优先级
     */
    public void analysis() {
        char[] origin =context.toCharArray();
        for (char c : origin) {
            //判断是不是终结符
            if (!level.containsKey(String.valueOf(c))) {
                stack.push(new ValueNode(String.valueOf(c)));//每一个可操作的数
            } else {
                if (operation.empty()) {
                    operation.push(String.valueOf(c));//运算符号
                } else {
                    combine(String.valueOf(c));
                }
            }
        }
    }

    /**
     * 判断操作符优先级
     *
     * @param left  操作符
     * @param right 操作符
     */
    private boolean compare(String left, String right) {
        return level.get(left) > level.get(right);
    }

    /**
     * 递归判断新加入操作符栈中新加入的操作符应该处于的位置，保证优先级高的操作符位于栈顶
     */
    private void combine(String curopt) {
        // peek方法返回栈顶元素但是不移除它
        if (compare(curopt, operation.peek())) {
            operation.push(curopt);
        } else {
            Node right = stack.pop();
            Node left = stack.pop();
            switch (operation.pop())    {
                case "*":
                    stack.push(new MulNode(left, right));
                    break;
                case "/":
                    stack.push(new DivNode(left, right));
                    break;
                case "-":
                    stack.push(new SubNode(left, right));
                    break;
                default:
                    stack.push(new AddNode(left, right));
                    break;
            }
            combine(curopt);
        }
    }
    public void setExpression(Node expression) {
        this.expression = expression;
    }
    public void execute() {
        analysis();
        expression=getExpression();
    }

}
